package com.yinuo.face;

import android.Manifest;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Rect;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.support.v8.renderscript.RenderScript;
import android.text.SpannableStringBuilder;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;

import com.arcsoft.facerecognition.AFR_FSDKEngine;
import com.arcsoft.facerecognition.AFR_FSDKFace;
import com.blankj.utilcode.util.FileIOUtils;
import com.blankj.utilcode.util.FileUtils;
import com.blankj.utilcode.util.ImageUtils;
import com.blankj.utilcode.util.SnackbarUtils;
import com.blankj.utilcode.util.SpanUtils;
import com.bumptech.glide.Glide;
import com.google.common.base.Strings;
import com.orhanobut.logger.Logger;
import com.raizlabs.android.dbflow.config.FlowManager;
import com.raizlabs.android.dbflow.sql.language.SQLite;
import com.raizlabs.android.dbflow.structure.ModelAdapter;
import com.tbruyelle.rxpermissions2.RxPermissions;
import com.yinuo.face.record.UserRecord;
import com.yinuo.face.record.UserRecordListActivity;
import com.yinuo.face.user.User;
import com.yinuo.face.user.UserListActivity;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import cc.cloudist.acplibrary.ACProgressConstant;
import cc.cloudist.acplibrary.ACProgressFlower;
import io.fotoapparat.Fotoapparat;
import io.fotoapparat.preview.Frame;
import io.fotoapparat.preview.FrameProcessor;
import io.fotoapparat.view.CameraView;
import io.github.silvaren.easyrs.tools.Nv21Image;
import io.github.silvaren.easyrs.tools.Resize;
import io.reactivex.functions.Consumer;

import static io.fotoapparat.selector.LensPositionSelectorsKt.front;

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener, Runnable {

    private final String dir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/face/record/";
    private Handler handler = new Handler(Looper.getMainLooper());
    private Map<String, User> userMap = new HashMap();
    private List<Rect> list = new ArrayList<>();
    private Fotoapparat fotoapparat;
    private RxPermissions rxPermissions;
    private RenderScript rs;
    private MediaPlayer media_success;
    private long lastSuccessTime = 0;
    private boolean isMatching = false;
    private CameraView cameraView;
    private View inflate;
    private ModelAdapter<UserRecord> recordModelAdapter;
    private ExecutorService executorService;
//    private RectanglesView rectanglesView;
    private Frame frame_current;
    private Rect rect_current;

    private FrameProcessor frameProcessor = new FrameProcessor() {
        @Override
        public void process(final Frame frame) {
            if (System.currentTimeMillis() - lastSuccessTime < 2000) {
                return;
            }
            final int width = frame.getSize().width;
            final int height = frame.getSize().height;
            final byte[] image = frame.getImage();

            ArcSdkEngine.getInstance().track(image, width, height, list);
            if (list.isEmpty() || isMatching) return;

            handler.post(new Runnable() {
                @Override
                public void run() {
//                    rectanglesView.setRectangles(list);
                }
            });


            isMatching = true;
            frame_current = new Frame(frame.getSize(), frame.getImage().clone(), frame.getRotation());
            rect_current = list.get(0);
            executorService.submit(MainActivity.this);
        }
    };
    @Override
    public void run() {
        try {
            int width = frame_current.getSize().width;
            int height = frame_current.getSize().height;
            byte[] image = frame_current.getImage();
            int rotation = frame_current.getRotation();

            AFR_FSDKFace feature = ArcSdkEngine.getInstance().feature(image, width, height, rect_current, rotation);
            final String valid = ArcSdkEngine.getInstance().valid(feature);
            if (Strings.isNullOrEmpty(valid)) return;

            lastSuccessTime = System.currentTimeMillis();
            Bitmap bitmap = Nv21Image.nv21ToBitmap(rs, image, width, height);
            Bitmap clip = ImageUtils.clip(bitmap, rect_current.left, rect_current.top, rect_current.width(), rect_current.height(), true);
            Bitmap bmp_save = ImageUtils.rotate(clip, 360 - rotation, 0, 0, true);

            final String fileName = dir + System.currentTimeMillis() + ".jpg";
            ImageUtils.save(bmp_save, fileName, Bitmap.CompressFormat.JPEG, true);

            handler.post(new Runnable() {
                @Override
                public void run() {
                    media_success.start();
                    User user = userMap.get(valid);
                    UserRecord userRecord = new UserRecord(UUID.randomUUID(), user.getUserName(), user.getUserIdentifier(), fileName, new Date());
                    recordModelAdapter.insert(userRecord);
                    SnackbarUtils.with(inflate).setMessage(getMsg(userRecord)).setBottomMargin(1).showSuccess();
                }
            });
        } catch (Exception e) {
            Logger.e(e, "识别异常");
        } finally {
            isMatching = false;
        }
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        DrawerLayout drawer = findViewById(R.id.drawer_layout);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.addDrawerListener(toggle);
        toggle.syncState();

        NavigationView navigationView = findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);

        inflate = findViewById(R.id.content);

        cameraView = findViewById(R.id.camera);

        rxPermissions = new RxPermissions(this);

        rs = RenderScript.create(this);

        recordModelAdapter = FlowManager.getModelAdapter(UserRecord.class);

        media_success = MediaPlayer.create(this, R.raw.success);

//        rectanglesView = findViewById(R.id.cameraRectView);

        executorService = Executors.newCachedThreadPool();

        final ActionBar supportActionBar = getSupportActionBar();
        supportActionBar.hide();

    }

    public void startCamera() {
        if (fotoapparat == null) {
            fotoapparat = Fotoapparat.with(this).lensPosition(front()).into(cameraView).frameProcessor(frameProcessor).build();
        }
        Logger.i("打开相机");
        fotoapparat.start();

    }

    private SpannableStringBuilder getMsg(UserRecord user) {
        Bitmap resize = Resize.resize(rs, BitmapFactory.decodeFile(user.getUserHeader()), 200, 200);
        return new SpanUtils()
                .appendImage(resize, SpanUtils.ALIGN_CENTER)
                .appendSpace(20)
                .append(user.getUserName()).setFontSize(28, true)
                .create();
    }

    @Override
    protected void onStart() {
        super.onStart();
        lastSuccessTime = System.currentTimeMillis();

        rxPermissions.request(Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE).subscribe(new Consumer<Boolean>() {
            @Override
            public void accept(Boolean aBoolean) throws Exception {
                Logger.i("所有授权状态:%s", aBoolean);
                startCamera();
            }
        });

        final ACProgressFlower dialog = new ACProgressFlower.Builder(this).direction(ACProgressConstant.DIRECT_CLOCKWISE).themeColor(Color.WHITE).text("正在重新加载人脸").fadeColor(Color.DKGRAY).build();
        dialog.show();

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                loadFaceRepository();
                dialog.cancel();
            }
        }, 1000);

        FileUtils.createOrExistsDir(dir);
    }

    private void loadFaceRepository() {
        ArcSdkEngine.getInstance().cleanCache();
        List<User> users = SQLite.select().from(User.class).queryList();
        for (User user : users) {
            String filePath = user.getUserHeader() + ".data";

            if (!FileUtils.isFileExists(filePath)) {
                Bitmap bitmap = BitmapFactory.decodeFile(user.getUserHeader());
                try {
                    Nv21Image nv21Image = Nv21Image.bitmapToNV21(rs, bitmap);
                    ArcSdkEngine.getInstance().detection(nv21Image.nv21ByteArray, nv21Image.width, nv21Image.height, list);
                    if (list.isEmpty()) continue;

                    AFR_FSDKFace afr_fsdkFace = ArcSdkEngine.getInstance().feature(nv21Image.nv21ByteArray, nv21Image.width, nv21Image.height, list.get(0), AFR_FSDKEngine.AFR_FOC_0);
                    if (afr_fsdkFace == null) continue;
                    FileIOUtils.writeFileFromBytesByStream(filePath, afr_fsdkFace.getFeatureData());
                } finally {
                    bitmap.recycle();
                }
            }

            byte[] faceData = FileIOUtils.readFile2BytesByChannel(filePath);
            ArcSdkEngine.getInstance().addToCache(user.getId().toString(), new AFR_FSDKFace(faceData));
            userMap.put(user.getId().toString(), user);
            Logger.d("添加人脸到比对模板:%s", user.getUserName());
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        fotoapparat.stop();
    }

    @Override
    public void onBackPressed() {
        DrawerLayout drawer = findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

    @SuppressWarnings("StatementWithEmptyBody")
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();

        if (id == R.id.nav_camera) {
            // Handle the camera action
        } else if (id == R.id.nav_user_list) {
            Intent intent = new Intent(MainActivity.this, UserListActivity.class);
            startActivity(intent);
        } else if (id == R.id.nav_user_record) {
            Intent intent = new Intent(MainActivity.this, UserRecordListActivity.class);
            startActivity(intent);
        } else if (id == R.id.nav_manage) {
            SnackbarUtils.with(inflate).setMessage("还在开发中....").setBottomMargin(1).showWarning();
        } else if (id == R.id.nav_share) {
            SnackbarUtils.with(inflate).setMessage("还在开发中....").setBottomMargin(1).showWarning();
        } else if (id == R.id.nav_send) {
            SnackbarUtils.with(inflate).setMessage("还在开发中....").setBottomMargin(1).showWarning();
        }

        DrawerLayout drawer = findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }

}
